#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getline.h>
#include <ctype.h>
#include <errno.h>
#include <errors.h>

#include "trapezoidal.h"

//int isFunAvailable (char *strPtr);
//int checkNum (char *strPtr, int isDouble);

/* This will check if the given function is available*/
int isFunAvailable (char *strPtr){
  int i =0;
  for (i = 0; i < nFns; i++){
    if (strcmp (strPtr, fns[i].name) == 0)
      return i;
  }
  return -1;
}

/* Pass 0/1 as 2nd argument to checkNum funtion to check if it is double or not */
int checkNum (char *strPtr, int isDouble){
  int i = 0;
  int flag = 0;
  
  if (strPtr[0] == '.'){
    return 1;
  }

  for (i = 0; i < strlen (strPtr); i++){
    if (strPtr[i] == '.'){
      if (flag == 0)
	flag = 1;
      else
	return 1;
    }
  }
  
  for (i = 0; i < strlen (strPtr); i ++){
    if (isDouble == 1){

      if (!isdigit((int)strPtr[i]) && strPtr[i] != 'e' && strPtr[i] != 'E' && strPtr[i] != '+' && strPtr[i] != '.' && 
	  strPtr[i] != '-'){
	return 1;
      }
    }
    else{
      if (!isdigit((int)strPtr[i])){
        return 1;
      }

    }
    /* Check for same operator does not occur. eg. 12++1, 12-+1, etc */
    if (strPtr[i] == '+' || strPtr[i] == '.' || strPtr[i] == '-'){
      if (!isdigit ((int)strPtr[i+1] )) {// (i+1) <= strlen (strPtr))){
	return 1;
      }
      if ( i != 0 && strPtr[i - 1] == ' ' && strPtr[i-1] == 'e'){
	return 1;
      }
    }
    if (strPtr[i] == 'e' || strPtr[i] == 'E'){
      if (!isdigit((int)strPtr[i+1]) && strlen (strPtr) <= i + 1){
	return 1;
      }
    }
  } 
  return 0;
}

int main (int argc, char *argv[]){

  double lo_bound = 0, hi_bound = 0, result;
  int n_intervals = 0, i = 0;
  char *line = NULL, *strPtr = NULL, *funPtr = NULL, *pEnd = NULL;
  int len = 0, fnNo, flag = 0;
  char ch;

  if (argc != 2){
    fprintf (stderr, "\nprj1: illegal input  \nUsage : prj1 trapezoidal\n\n");
    exit(1);
  }

  if(strcmp (argv[1], "trapezoidal")){
    fprintf (stderr, "prj1: illegal input: %s \nUsage : prj1 trapezoidal\n\n",argv[1]);
    exit (1);
  }

  do{
    fflush (stdout);
    fflush (stdin);
    fprintf (stdout,"___________________________\n");
    fprintf (stdout, "\nAvailable Functions (FN):\n");
    for (i = 0; i < nFns; i++){
      fprintf (stdout, "\t%d) %s\n", i+1 ,fns[i].name);
    }
    fprintf (stdout,"___________________________\n");
    fprintf (stdout, "\nEnter the values for \nFN LO_BOUND HI_BOUND N_INTERVALES\n");
    
    line = (char *)malloc (sizeof (char));
    if (!line){
      fprintf (stderr, "Not enough memory\n");
      exit(1);
    }
    if (getline (stdin, &line, &len) == -1){
      fprintf (stderr, "ERROR: Unable to read line\n");
      exit(1);
    }

    /* scan line and parse individual entry */
    i = 0;
    strPtr = strtok (line, " \n");
    while (strPtr != NULL){

      if ( i == 0){
	/* Check if the funtion is available in fns[] */
	if ((fnNo = isFunAvailable (strPtr)) != -1){
	  funPtr = strPtr;
	}
	else{
	  fprintf (stderr, "\nERROR: Function \"%s\" is not defined\n", strPtr);
	  flag = 1;
	  break;
	}
      }

      if ( i == 1){
	/* Pass 1 as 2nd argument to checkNum funtion if the entered value is double */
	if (checkNum(strPtr, 1) == 0){
	  lo_bound = strtod (strPtr, &pEnd);	  
	}
	else{
	  fprintf (stderr, "\nERROR: Invalid LO_BOUND value : %s\n", strPtr);
	  flag = 1;
	  break;
	}
      }

      if ( i == 2){
	if (checkNum (strPtr, 1) == 0){
          hi_bound = strtod (strPtr, &pEnd);
        }
        else{
          fprintf (stderr, "\nERROR: Invalid HI_BOUND value : %s\n", strPtr);
          flag = 1;
	  break;
        }
      }

      if ( i == 3){
	/* Pass 0 as 2nd argument to checkNum funtion if the entered value is not double */
        if (checkNum (strPtr, 0) == 0){
          n_intervals = atoi (strPtr);
        }
        else{
          fprintf (stderr, "\nERROR: Invalid N_INTERVALS : %s\n", strPtr);
          flag = 1;
	  break;
        }
      }

      if ( i >= 4){
          fprintf (stderr, "\nERROR: Illegal input %s\n", strPtr);
          flag = 1;
	  break;
      }
     
      i++;
      /* Read next argument from line by using strtok */
      strPtr = strtok (NULL, " \n");
    }
    
    i--;
    /* Compute the trapezoidal result when only the value of flag is 0 and count for entered arguments is proper */
    if ( flag == 0 && i == 3){
      result = trapezoidal(fns[fnNo].f, lo_bound, hi_bound, n_intervals);
      if (result == -0)
	result = 0;
      printf ("\nResult of integral of \'%s\' function using Trapezoidal Rule: %.6g\n", fns[fnNo].name, result);
    }
    else{ /* Give error in case of insufficient arguments */
      if (flag == 0){
	fprintf (stdout, "\nERROR: Insufficient values provided\n");
      }
    }

    /* Free the line before returning. Free it only if it has data */
    if (line)
      free (line);

    flag = 0;
    fprintf (stdout, "\nQuit? (y/n) : ");
    scanf ("%c",&ch);
  }while (ch != 'y');
  return 0;
}
